// need the d3d.h for things in format of .dds file
#include "StdAfx.h"

#include <ddraw.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "../eterBase/MappedFile.h"
#include "../eterBase/Debug.h"

#include "DXTCImage.h"

struct DXTColBlock
{
	WORD col0;
	WORD col1;
	
	// no bit fields - use bytes
	BYTE row[4];
};

struct DXTAlphaBlockExplicit
{
	WORD row[4];
};

struct DXTAlphaBlock3BitLinear
{
	BYTE alpha0;
	BYTE alpha1;
	
	BYTE stuff[6];
};

// use cast to struct instead of RGBA_MAKE as struct is much
struct Color8888
{
	BYTE b;		// Last one is MSB, 1st is LSB.
	BYTE g;		// order of the output ARGB or BGRA, etc...
	BYTE r;		// change the order of names to change the 
	BYTE a;
};

struct Color565
{
	unsigned nBlue  : 5;		// order of names changes
	unsigned nGreen : 6;		//  byte order of output to 32 bit
	unsigned nRed	: 5;
};

/////////////////////////////////////
// should be in ddraw.h
#ifndef MAKEFOURCC
#define MAKEFOURCC(ch0, ch1, ch2, ch3)                                      \
				((DWORD)(BYTE) (ch0       ) | ((DWORD)(BYTE) (ch1) <<  8) | \
				((DWORD)(BYTE) (ch2) << 16) | ((DWORD)(BYTE) (ch3) << 24))
#endif // defined(MAKEFOURCC)

CDXTCImage::CDXTCImage()
{
	Initialize();
}

CDXTCImage::~CDXTCImage()
{
}

void CDXTCImage::Initialize()
{
	m_nWidth = 0;
	m_nHeight = 0;

	for (int i = 0; i < MAX_MIPLEVELS; ++i)
		m_pbCompBufferByLevels[i] = NULL;
}

void CDXTCImage::Clear()
{
	for (int i = 0; i < MAX_MIPLEVELS; ++i)
		m_bCompVector[i].clear();

	Initialize();
}

bool CDXTCImage::LoadFromFile(const char * filename)
{
	// only understands .dds files for now
	// return true if success
	char * exts[] = { ".DDS" };
	int next = 1;
	
	static char fileupper[MAX_PATH+1];
	
	strncpy(fileupper, filename, MAX_PATH); 
	strupr(fileupper);
	
	int i;
	bool knownformat = false;
	
	for (i = 0; i < next; ++i)
	{
		char * found = strstr(fileupper, exts[0]);
		
		if (found != NULL)
		{
			knownformat = true;
			break;
		}
	}
	
	if (knownformat == false)
	{
		Tracef("Unknown file format encountered! [%s]\n", filename);
		return(false);
	}

	CMappedFile mappedFile;
	LPCVOID pvMap;

	if (!mappedFile.Create(filename, &pvMap, 0, 0))
	{
		Tracef("Can't open file for reading! [%s]\n", filename);
		return false;
	}

	return LoadFromMemory((const BYTE*) pvMap);
}

bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap)
{
	//////////////////////////////////////
	// start reading the file
	// from Microsoft's mssdk D3DIM example "Compress"
	DWORD dwMagic;
	
	// Read magic number
	dwMagic = *(DWORD *) c_pbMap;
	c_pbMap += sizeof(DWORD);

//!@#
//	if (dwMagic != MAKEFOURCC('D','D','S',' '))
//		return false;
	
	DDSURFACEDESC2 ddsd; // read from dds file
	
	// Read the surface description
	memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2));
	c_pbMap += sizeof(DDSURFACEDESC2);
	
	// Does texture have mipmaps?
	m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE;
	
	// Clear unwanted flags
	// Can't do this!!!  surface not re-created here
	//    ddsd.dwFlags &= (~DDSD_PITCH);
	//    ddsd.dwFlags &= (~DDSD_LINEARSIZE);

	// Is it DXTC ?
	// I sure hope pixelformat is valid!
	m_xddPixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags;
	m_xddPixelFormat.dwFourCC = ddsd.ddpfPixelFormat.dwFourCC;
	m_xddPixelFormat.dwSize = ddsd.ddpfPixelFormat.dwSize;
	m_xddPixelFormat.dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount;
	m_xddPixelFormat.dwRGBAlphaBitMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
	m_xddPixelFormat.dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask;
	m_xddPixelFormat.dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask;
	m_xddPixelFormat.dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask;

	DecodePixelFormat(m_strFormat, &m_xddPixelFormat);
	
	if (m_CompFormat != PF_DXT1 &&
		m_CompFormat != PF_DXT3 &&
		m_CompFormat != PF_DXT5)
	{
		return false;
	}

	if (ddsd.dwMipMapCount > MAX_MIPLEVELS)
		ddsd.dwMipMapCount = MAX_MIPLEVELS;

	m_nWidth		= ddsd.dwWidth;
	m_nHeight		= ddsd.dwHeight;
	//!@#
	m_dwMipMapCount = max(1, ddsd.dwMipMapCount);
	m_dwFlags		= ddsd.dwFlags;

	if (ddsd.dwFlags & DDSD_PITCH)
	{
		m_lPitch = ddsd.lPitch;
		m_pbCompBufferByLevels[0] = c_pbMap;
	}
	else
	{
		m_lPitch = ddsd.dwLinearSize;

		if (ddsd.dwFlags & DDSD_MIPMAPCOUNT)
		{
			for (DWORD dwLinearSize = ddsd.dwLinearSize, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2)
			{
				m_pbCompBufferByLevels[i] = c_pbMap;
				c_pbMap += dwLinearSize;
			}
		}
		else
		{
			m_pbCompBufferByLevels[0] = c_pbMap;
		}
	}

	return true;
}

//////////////////////////////////////////////////////////////////////
bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap)
{
	if (!LoadHeaderFromMemory(c_pbMap))
		return false;

	if (m_dwFlags & DDSD_PITCH)
	{
		DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8;

		m_nCompSize = m_lPitch * m_nHeight;
		m_nCompLineSz = dwBytesPerRow;

		m_bCompVector[0].resize(m_nCompSize);
		BYTE * pDest = &m_bCompVector[0][0];

		c_pbMap = m_pbCompBufferByLevels[0];

		for (int yp = 0; yp < m_nHeight; ++yp)
		{
			memcpy(pDest, c_pbMap, dwBytesPerRow);
			pDest += m_lPitch;
			c_pbMap += m_lPitch;
		}
	}
	else
	{
		if (m_dwFlags & DDSD_MIPMAPCOUNT)
		{
			for (DWORD dwLinearSize = m_lPitch, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2)
			{
				m_bCompVector[i].resize(dwLinearSize);
				Copy(i, &m_bCompVector[i][0], dwLinearSize);
			}
		}
		else
		{
			m_bCompVector[0].resize(m_lPitch);
			Copy(0, &m_bCompVector[0][0], m_lPitch);
		}
	}

	// done reading file
	return true;
}

bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long lDestPitch)
{
	if (!(m_dwFlags & DDSD_MIPMAPCOUNT))
		if (miplevel)
			return false;

	/*
	DXTColBlock * pBlock;
	WORD * pPos = (WORD *) &m_pbCompBufferByLevels[miplevel][0];
	int xblocks = (m_nWidth >> miplevel) / 4;
	int yblocks = (m_nHeight >> miplevel) / 4;

	for (int y = 0; y < yblocks; ++y)
	{
		// 8 bytes per block
		pBlock = (DXTColBlock*) ((DWORD) pPos + y * xblocks * 8);

		memcpy(pbDest, pBlock, xblocks * 8);
		pbDest += lDestPitch;
	}
	*/

	memcpy(pbDest, m_pbCompBufferByLevels[miplevel], m_lPitch >> (miplevel * 2));
	pbDest += lDestPitch;
	return true;
}

void CDXTCImage::Unextract(BYTE * pbDest, int /*iWidth*/, int /*iHeight*/, int iPitch)
{
	if (!m_pbCompBufferByLevels[0])
		return;

	DXTColBlock * pBlock;
	BYTE * pPos = (BYTE *) &m_pbCompBufferByLevels[0][0];
	int xblocks = m_nWidth / 4;
	int yblocks = (m_nHeight / 4) * ((iPitch / m_nWidth) / 2);

	for (int y = 0; y < yblocks; ++y)
	{
		pBlock = (DXTColBlock*) (pPos + y * xblocks * 8);

		memcpy(pbDest, pBlock, xblocks * 8);
		pbDest += xblocks * 8;
	}

	/*
	for (int y = 0; y < iHeight; ++y)
	{
		memcpy(pbDest, &m_pbCompBufferByLevels[0][0] + y*iWidth, iWidth);
		pbDest += iWidth;
	}
	*/
}

void CDXTCImage::Decompress(int miplevel, DWORD * pdwDest)
{
	switch (m_CompFormat)
	{
		case PF_DXT1:
			DecompressDXT1(miplevel, pdwDest);
			break;

		case PF_DXT3:
			DecompressDXT3(miplevel, pdwDest);
			break;
			
		case PF_DXT5:
			DecompressDXT5(miplevel, pdwDest);
			break;
			
		case PF_ARGB:
			DecompressARGB(miplevel, pdwDest);
			break;

		case PF_UNKNOWN:
			break;
	}
}

inline void GetColorBlockColors(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, 
								Color8888 * col_2, Color8888 * col_3,
								WORD & wrd)
{
	// There are 4 methods to use - see the Time_ functions.
	// 1st = shift = does normal approach per byte for color comps
	// 2nd = use freak variable bit field color565 for component extraction
	// 3rd = use super-freak DWORD adds BEFORE shifting the color components
	//  This lets you do only 1 add per color instead of 3 BYTE adds and
	//  might be faster
	// Call RunTimingSession() to run each of them & output result to txt file
	
	// freak variable bit structure method
	// normal math
	// This method is fastest
	Color565 * pCol;
	
	pCol = (Color565*) & (pBlock->col0);
	
	col_0->a = 0xff;
	col_0->r = pCol->nRed;
	col_0->r <<= 3;				// shift to full precision
	col_0->g = pCol->nGreen;
	col_0->g <<= 2;
	col_0->b = pCol->nBlue;
	col_0->b <<= 3;
	
	pCol = (Color565*) & (pBlock->col1);
	col_1->a = 0xff;
	col_1->r = pCol->nRed;
	col_1->r <<= 3;				// shift to full precision
	col_1->g = pCol->nGreen;
	col_1->g <<= 2;
	col_1->b = pCol->nBlue;
	col_1->b <<= 3;
	
	if (pBlock->col0 > pBlock->col1)
	{
		// Four-color block: derive the other two colors.    
		// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block.
		wrd = (WORD) (((WORD) col_0->r * 2 + (WORD) col_1->r) / 3);
		// no +1 for rounding
		// as bits have been shifted to 888
		col_2->r = (BYTE)wrd;
		
		wrd = (WORD) (((WORD) col_0->g * 2 + (WORD) col_1->g) / 3);
		col_2->g = (BYTE)wrd;
		
		wrd = (WORD) (((WORD) col_0->b * 2 + (WORD) col_1->b) / 3);
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r * 2) / 3);
		col_3->r = (BYTE)wrd;
		
		wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g * 2) / 3);
		col_3->g = (BYTE)wrd;
		
		wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b * 2) / 3);
		col_3->b = (BYTE)wrd;
		col_3->a = 0xff;
	}
	else
	{
		// Three-color block: derive the other color.
		// 00 = color_0,  01 = color_1,  10 = color_2,  
		// 11 = transparent.
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block. 
		
		// explicit for each component, unlike some refrasts...
		
		// Tracef("block has alpha\n");
		wrd = (WORD) (((WORD) col_0->r + (WORD) col_1->r) / 2);
		col_2->r = (BYTE)wrd;
		wrd = (WORD) (((WORD) col_0->g + (WORD) col_1->g) / 2);
		col_2->g = (BYTE)wrd;
		wrd = (WORD) (((WORD) col_0->b + (WORD) col_1->b) / 2);
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		col_3->r = 0x00;		// random color to indicate alpha
		col_3->g = 0x00;
		col_3->b = 0x00;
		col_3->a = 0x00;
	}
} // Get color block colors (...)


inline void DecodeColorBlock(DWORD * pImPos,
							 DXTColBlock * pColorBlock,
							 int width,
							 DWORD * col_0,
							 DWORD * col_1,
							 DWORD * col_2,
							 DWORD * col_3)
{
	// width is width of image in pixels
	DWORD bits;
	int y, n;
	
	// bit masks = 00000011, 00001100, 00110000, 11000000
	const DWORD masks[] = { 3, 12, 3 << 4, 3 << 6 };
	const int   shift[] = { 0, 2, 4, 6 };
	
	// r steps through lines in y
	for (y = 0; y < 4; ++y, pImPos += width - 4) // no width * 4 as DWORD ptr inc will * 4
	{
		// width * 4 bytes per pixel per line
		// each j dxtc row is 4 lines of pixels
		
		// pImPos = (DWORD*) ((DWORD) pBase + i * 16 + (y + j * 4) * m_nWidth * 4);

		// n steps through pixels
		for (n = 0; n < 4; ++n)
		{
			bits = pColorBlock->row[y] & masks[n];
			bits >>= shift[n];

			switch (bits)
			{
				case 0:
					*pImPos = *col_0;
					pImPos++; // increment to next DWORD
					break;

				case 1:
					*pImPos = *col_1;
					pImPos++;
					break;

				case 2:
					*pImPos = *col_2;
					pImPos++;
					break;

				case 3:
					*pImPos = *col_3;
					pImPos++;
					break;

				default:
					Tracef("Your logic is jacked! bits == 0x%x\n", bits);
					pImPos++;
					break;
			}
		}
	}
}

inline void DecodeAlphaExplicit(DWORD * pImPos, DXTAlphaBlockExplicit * pAlphaBlock,
								int width, DWORD alphazero)
{
	// alphazero is a bit mask that when & with the image color
	//  will zero the alpha bits, so if the image DWORDs  are
	//  ARGB then alphazero will be 0x00ffffff or if
	//  RGBA then alphazero will be 0xffffff00
	//  alphazero constructed automaticaly from field order of Color8888 structure

	// decodes to 32 bit format only
	int row, pix;

	WORD wrd;

	Color8888 col;
	col.r = col.g = col.b = 0;

	//Tracef("\n");	
	for (row = 0; row < 4; row++, pImPos += width - 4)
	{
		// pImPow += pImPos += width-4 moves to next row down
		wrd = pAlphaBlock->row[row];

		// Tracef("0x%.8x\t\t", wrd);
		for (pix = 0; pix < 4; ++pix)
		{
			// zero the alpha bits of image pixel
			*pImPos &= alphazero;

			col.a = (BYTE) (wrd & 0x000f);		// get only low 4 bits
			//			col.a <<= 4;				// shift to full byte precision
			// NOTE:  with just a << 4 you'll never have alpha
			// of 0xff,  0xf0 is max so pure shift doesn't quite
			// cover full alpha range.
			// It's much cheaper than divide & scale though.
			// To correct for this, and get 0xff for max alpha,
			//  or the low bits back in after left shifting
			col.a = (BYTE) (col.a | (col.a << 4));	// This allows max 4 bit alpha to be 0xff alpha
			//  in final image, and is crude approach to full 
			//  range scale

			*pImPos |= *((DWORD*)&col);	// or the bits into the prev. nulled alpha

			wrd >>= 4; // move next bits to lowest 4

			pImPos++; // move to next pixel in the row
		}
	}
}

static BYTE			gBits[4][4];
static WORD			gAlphas[8];
static Color8888	gACol[4][4];

inline void DecodeAlpha3BitLinear(DWORD * pImPos, DXTAlphaBlock3BitLinear * pAlphaBlock,
								  int width, DWORD alphazero)
{
	gAlphas[0] = pAlphaBlock->alpha0;
	gAlphas[1] = pAlphaBlock->alpha1;

	// 8-alpha or 6-alpha block?    
	if (gAlphas[0] > gAlphas[1])
	{
		// 8-alpha block:  derive the other 6 alphas.    
		// 000 = alpha_0, 001 = alpha_1, others are interpolated
		gAlphas[2] = (WORD) ((6 * gAlphas[0] +     gAlphas[1]) / 7);	// Bit code 010
		gAlphas[3] = (WORD) ((5 * gAlphas[0] + 2 * gAlphas[1]) / 7);	// Bit code 011    
		gAlphas[4] = (WORD) ((4 * gAlphas[0] + 3 * gAlphas[1]) / 7);	// Bit code 100    
		gAlphas[5] = (WORD) ((3 * gAlphas[0] + 4 * gAlphas[1]) / 7);	// Bit code 101
		gAlphas[6] = (WORD) ((2 * gAlphas[0] + 5 * gAlphas[1]) / 7);	// Bit code 110    
		gAlphas[7] = (WORD) ((    gAlphas[0] + 6 * gAlphas[1]) / 7);	// Bit code 111
	}    
	else
	{
		// 6-alpha block:  derive the other alphas.    
		// 000 = alpha_0, 001 = alpha_1, others are interpolated
		gAlphas[2] = (WORD) ((4 * gAlphas[0] +     gAlphas[1]) / 5);	// Bit code 010
		gAlphas[3] = (WORD) ((3 * gAlphas[0] + 2 * gAlphas[1]) / 5);	// Bit code 011    
		gAlphas[4] = (WORD) ((2 * gAlphas[0] + 3 * gAlphas[1]) / 5);	// Bit code 100    
		gAlphas[5] = (WORD) ((   gAlphas[0] + 4 * gAlphas[1]) / 5);		// Bit code 101
		gAlphas[6] = 0;													// Bit code 110
		gAlphas[7] = 255;												// Bit code 111
	}
	
	// Decode 3-bit fields into array of 16 BYTES with same value
	
	// first two rows of 4 pixels each:
	// pRows = (Alpha3BitRows*) & (pAlphaBlock->stuff[0]);
	const DWORD mask = 0x00000007;		// bits = 00 00 01 11
	DWORD bits = *((DWORD*) & (pAlphaBlock->stuff[0]));
	
	gBits[0][0] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[0][1] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[0][2] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[0][3] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[1][0] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[1][1] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[1][2] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[1][3] = (BYTE) (bits & mask);
	
	// now for last two rows:
	bits = *((DWORD*) & (pAlphaBlock->stuff[3]));		// last 3 bytes
	
	gBits[2][0] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[2][1] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[2][2] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[2][3] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[3][0] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[3][1] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[3][2] = (BYTE) (bits & mask);
	bits >>= 3;
	gBits[3][3] = (BYTE) (bits & mask);
	
	// decode the codes into alpha values
	int row, pix;
	
	for (row = 0; row < 4; ++row)
	{
		for (pix = 0; pix < 4; ++pix)
		{
			gACol[row][pix].a = (BYTE) gAlphas[gBits[row][pix]];
			
			assert(gACol[row][pix].r == 0);
			assert(gACol[row][pix].g == 0);
			assert(gACol[row][pix].b == 0);
		}
	}
	
	// Write out alpha values to the image bits	
	for (row = 0; row < 4; ++row, pImPos += width - 4)
	{
		// pImPow += pImPos += width - 4 moves to next row down
		for (pix = 0; pix < 4; ++pix)
		{
			// zero the alpha bits of image pixel
			*pImPos &= alphazero;
			*pImPos |= *((DWORD*) &(gACol[row][pix]));	// or the bits into the prev. nulled alpha
			pImPos++;
		}
	}
}

void CDXTCImage::DecompressDXT1(int miplevel, DWORD * pdwDest)
{
	// This was hacked up pretty quick & slopily
	// decompresses to 32 bit format 0xARGB
	int xblocks, yblocks;
#ifdef DEBUG
	if ((ddsd.dwWidth % 4) != 0)
	{
		Tracef("****** warning width not div by 4!  %d\n", ddsd.dwWidth);
	}
	
	if ((ddsd.dwHeight % 4) != 0)
	{
		Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight);
	}
	
	Tracef("end check\n");
#endif
	UINT nWidth = m_nWidth >> miplevel;
	UINT nHeight = m_nHeight >> miplevel;
	
	xblocks = nWidth / 4;
	yblocks = nHeight / 4;

	int		x, y;
	DWORD * pBase	= (DWORD *) pdwDest;
	WORD  * pPos	= (WORD *) &m_bCompVector[miplevel][0];;	// pos in compressed data
	DWORD * pImPos;

	DXTColBlock	* pBlock;

	Color8888 col_0, col_1, col_2, col_3;
	WORD wrd;

	for (y = 0; y < yblocks; ++y)
	{
		// 8 bytes per block
		pBlock = (DXTColBlock *) ((DWORD) pPos + y * xblocks * 8);
		
		for (x = 0; x < xblocks; ++x, ++pBlock)
		{
			// inline func:
			GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);

			pImPos = (DWORD *) ((DWORD) pBase + x*16 + (y*4) * nWidth * 4);
			DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3);
			// Set to RGB test pattern
			//	pImPos = (DWORD*) ((DWORD) pBase + i * 4 + j * m_nWidth * 4);
			//	*pImPos = ((i * 4) << 16) | ((j * 4) << 8) | ((63 - i) * 4);

			// checkerboard of only col_0 and col_1 basis colors:
			//	pImPos = (DWORD *) ((DWORD) pBase + i * 8 + j * m_nWidth * 8);
			//	*pImPos = *((DWORD *) &col_0);
			//	pImPos += 1 + m_nWidth;
			//	*pImPos = *((DWORD *) &col_1);
		}
	}
}

void CDXTCImage::DecompressDXT3(int miplevel, DWORD* pdwDest)
{
	int xblocks, yblocks;
#ifdef DEBUG
	if ((ddsd.dwWidth % 4) != 0)
	{
		Tracef("****** warning width not div by 4! %d\n", ddsd.dwWidth);
	}
	
	if ((ddsd.dwHeight % 4) != 0)
	{
		Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight);
	}
	
	Tracef("end check\n");
#endif 
	UINT nWidth = m_nWidth >> miplevel;
	UINT nHeight = m_nHeight >> miplevel;

	xblocks = nWidth / 4;
	yblocks = nHeight / 4;

	int		x, y;
	DWORD * pBase	= (DWORD *) pdwDest;
	WORD  * pPos	= (WORD *) &m_bCompVector[miplevel][0]; // pos in compressed data
	DWORD * pImPos;	// pos in decompressed data

	DXTColBlock	* pBlock;
	DXTAlphaBlockExplicit * pAlphaBlock;

	Color8888 col_0, col_1, col_2, col_3;
	WORD wrd;

	// fill alphazero with appropriate value to zero out alpha when
	//  alphazero is ANDed with the image color 32 bit DWORD:
	col_0.a = 0;
	col_0.r = col_0.g = col_0.b = 0xff;

	DWORD alphazero = *((DWORD *) &col_0);

	for (y = 0; y < yblocks; ++y)
	{
		// 8 bytes per block
		// 1 block for alpha, 1 block for color
		pBlock = (DXTColBlock *) ((DWORD) (pPos + y * xblocks * 16));

		for (x = 0; x < xblocks; ++x, ++pBlock)
		{
			// inline
			// Get alpha block
			pAlphaBlock = (DXTAlphaBlockExplicit *) pBlock;
			
			// inline func:
			// Get color block & colors
			pBlock++;
			GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
			
			// Decode the color block into the bitmap bits
			// inline func:
			pImPos = (DWORD *) ((DWORD) (pBase + x * 16 + (y * 4) * nWidth * 4));
			
			DecodeColorBlock(pImPos,
							 pBlock, 
							 nWidth,
							 (DWORD *) &col_0, (DWORD *) &col_1, (DWORD *) &col_2, (DWORD *) &col_3);
			
			// Overwrite the previous alpha bits with the alpha block
			//  info
			// inline func:
			DecodeAlphaExplicit(pImPos, pAlphaBlock, nWidth, alphazero);
		}
	}
}

void CDXTCImage::DecompressDXT5(int level, DWORD * pdwDest)
{
	int xblocks, yblocks;
#ifdef DEBUG
	if ((ddsd.dwWidth % 4) != 0)
	{
		Tracef("****** warning width not div by 4! %d\n", ddsd.dwWidth);
	}
	
	if ((ddsd.dwHeight % 4) != 0)
	{
		Tracef("****** warning Height not div by 4! %d\n", ddsd.dwHeight);
	}
	
	Tracef("end check\n");
#endif
	UINT nWidth = m_nWidth >> level;
	UINT nHeight = m_nHeight >> level;

	xblocks = nWidth / 4;
	yblocks = nHeight / 4;

	int x, y;
	
	DWORD * pBase = (DWORD *) pdwDest;
	WORD  * pPos = pPos = (WORD *) &m_bCompVector[level][0]; // pos in compressed data
	DWORD * pImPos;	// pos in decompressed data

	DXTColBlock	* pBlock;
	DXTAlphaBlock3BitLinear * pAlphaBlock;
	
	Color8888 col_0, col_1, col_2, col_3;
	WORD wrd;
	
	// fill alphazero with appropriate value to zero out alpha when
	// alphazero is ANDed with the image color 32 bit DWORD:
	col_0.a = 0;
	col_0.r = col_0.g = col_0.b = 0xff;
	DWORD alphazero = *((DWORD *) &col_0);
	
	////////////////////////////////
	// Tracef("blocks: x: %d y: %d\n", xblocks, yblocks);
	for (y = 0; y < yblocks; ++y)
	{
		// 8 bytes per block
		// 1 block for alpha, 1 block for color
		pBlock = (DXTColBlock*) ((DWORD) (pPos + y * xblocks * 16));

		for (x = 0; x < xblocks; ++x, ++pBlock)
		{
			// inline
			// Get alpha block
			pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
			
			// inline func:
			// Get color block & colors
			pBlock++;
			
			// Tracef("pBlock: 0x%.8x\n", pBlock);
			GetColorBlockColors(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
			
			// Decode the color block into the bitmap bits
			// inline func:
			pImPos = (DWORD *) ((DWORD) (pBase + x * 16 + (y * 4) * nWidth * 4));

			//DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3);
			DecodeColorBlock(pImPos, pBlock, nWidth, (DWORD *)&col_0, (DWORD *)&col_1, (DWORD *)&col_2, (DWORD *)&col_3);

			// Overwrite the previous alpha bits with the alpha block
			//  info
			DecodeAlpha3BitLinear(pImPos, pAlphaBlock, nWidth, alphazero);
		}
	}
}	// dxt5

void CDXTCImage::DecompressARGB(int level, DWORD * pdwDest)
{
	UINT lPitch = m_lPitch >> (level * 2);
	memcpy(pdwDest, &m_bCompVector[level][0], lPitch);
}
/*
typedef struct _DDSURFACEDESC2 {
DWORD         dwSize;
DWORD         dwFlags;
DWORD         dwHeight;
DWORD         dwWidth;
union
{
LONG      lPitch;
DWORD     dwLinearSize;
} DUMMYUNIONNAMEN(1);
DWORD         dwBackBufferCount;
union
{
DWORD     dwMipMapCount;
DWORD     dwRefreshRate;
} DUMMYUNIONNAMEN(2);
DWORD         dwAlphaBitDepth;
DWORD         dwReserved;
LPVOID        lpSurface;
union
{
DDCOLORKEY    ddckCKDestOverlay;
DWORD         dwEmptyFaceColor;
} DUMMYUNIONNAMEN(3);
DDCOLORKEY    ddckCKDestBlt;
DDCOLORKEY    ddckCKSrcOverlay;
DDCOLORKEY    ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS2      ddsCaps;
DWORD         dwTextureStage;
} DDSURFACEDESC2, FAR* LPDDSURFACEDESC2; 
*/

//-----------------------------------------------------------------------------
// Name: GetNumberOfBits()
// Desc: Returns the number of bits set in a DWORD mask
//	from microsoft mssdk d3dim sample "Compress"
//-----------------------------------------------------------------------------
static WORD GetNumberOfBits(DWORD dwMask)
{
	WORD wBits;
    for (wBits = 0; dwMask; wBits++)
        dwMask = (dwMask & (dwMask - 1)); 
	
    return wBits;
}

//-----------------------------------------------------------------------------
// Name: PixelFormatToString()
// Desc: Creates a string describing a pixel format.
//	adapted from microsoft mssdk D3DIM Compress example
//  PixelFormatToString()
//-----------------------------------------------------------------------------
VOID CDXTCImage::DecodePixelFormat(CHAR* strPixelFormat, XDDPIXELFORMAT* pxddpf)
{
	switch (pxddpf->dwFourCC)
	{
		case 0:
			{
				// This dds texture isn't compressed so write out ARGB format
				WORD a = GetNumberOfBits(pxddpf->dwRGBAlphaBitMask);
				WORD r = GetNumberOfBits(pxddpf->dwRBitMask);
				WORD g = GetNumberOfBits(pxddpf->dwGBitMask);
				WORD b = GetNumberOfBits(pxddpf->dwBBitMask);

				_snprintf(strPixelFormat, 31, "ARGB-%d%d%d%d%s", a, r, g, b,
					pxddpf->dwBBitMask & DDPF_ALPHAPREMULT ? "-premul" : "");
				m_CompFormat = PF_ARGB;
			}
			break;
			
		case MAKEFOURCC('D','X','T','1'):
			strncpy(strPixelFormat, "DXT1", 31);
			m_CompFormat = PF_DXT1;
			break;
			
		case MAKEFOURCC('D','X','T','2'):
			strncpy(strPixelFormat, "DXT2", 31);
			m_CompFormat = PF_DXT2;
			break;
			
		case MAKEFOURCC('D','X','T','3'):
			strncpy(strPixelFormat, "DXT3", 31);
			m_CompFormat = PF_DXT3;
			break;
			
		case MAKEFOURCC('D','X','T','4'):
			strncpy(strPixelFormat, "DXT4", 31);
			m_CompFormat = PF_DXT4;
			break;
			
		case MAKEFOURCC('D','X','T','5'):
			strncpy(strPixelFormat, "DXT5", 31);
			m_CompFormat = PF_DXT5;
			break;

		default:
			strcpy(strPixelFormat, "Format Unknown");
			m_CompFormat = PF_UNKNOWN;
			break;
	}
}

/*					  
// Struct to hold various timing values
struct TimingInfo
{	
	LARGE_INTEGER	m_start_clk;
	LARGE_INTEGER	m_end_clk;
	
	int			m_nSamples;
	LARGE_INTEGER	m_interval_sum;		// sum of all end-start, nSamples number added in
	
	CString		m_csName;		// text desc of what timed
};
  
void CDXTCImage::RunTimingSession()
{
	// Must have a dxt5 texture loaded
	// No special reason - just lazy coding
	// Functions called to time code are separate from non-timed
	//  code.  It's alogorithm that counts.
	ASSERT(m_pCompBytes != NULL);
	ASSERT(m_pDecompBytes != NULL);		// must already have allocated memory
	
	switch (m_CompFormat)
	{
		case PF_DXT1:
		case PF_DXT2:
		case PF_DXT3:
		case PF_DXT4:
		case PF_UNKNOWN:
			Tracef("You must have a DXT5 texture loaded to RunTimingSession()!!\n");
			Tracef("Now I will be nasty and ASSERT(false)!\n");
			ASSERT(false);
			break;
			
		case PF_DXT5:
			Tracef("Running code timing session on DXT5 color decompress\n");
			break;
	}
	
	LARGE_INTEGER	start_clk, end_clk;
	QueryPerformanceCounter(&start_clk);
#define NMETHOD   4
#define NBATCHES  4
	int passes[NBATCHES];
	passes[0] = 1;
	passes[1] = 10;
	passes[2] = 30; 
	passes[3] = 50;
	
	TimingInfo method[NMETHOD][NBATCHES];
	
	int i, n;
	
	FILE * pf = fopen("timing.txt", "wt");
	
	if (pf == NULL)
	{
		return;
	}
	
	fprintf(pf, "\n\n");
	
	for (i = 0; i < NBATCHES; ++i)
	{
		Sleep(50);
		fprintf(pf,"i: %d passes[i]: %d\n", i, passes[i]);
		Time_Decomp5_01(passes[i], &(method[0][i]));
		Time_Decomp5_02(passes[i], &(method[1][i]));
		Time_Decomp5_03(passes[i], &(method[2][i]));
		Time_Decomp5_04(passes[i], &(method[3][i]));
	}
	
	QueryPerformanceCounter(&end_clk);
	
	//	unsigned long total;
	//	total = (unsigned long) (end_clk - start_clk);
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(& freq);
	
	fprintf(pf, "\nCounter freq = %u  %d \n", freq.LowPart, freq.HighPart);
	fprintf(pf, "start:  %u  %u       end:  %u  %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart);
	
	Tracef("\nCounter freq = %u  %d \n", freq.LowPart, freq.HighPart);
	Tracef("start:  %u  %u       end:  %u  %u\n", start_clk.LowPart, start_clk.HighPart, end_clk.LowPart, end_clk.HighPart);
	
	double dur = ((double)end_clk.LowPart - (double)start_clk.LowPart) / (double)freq.LowPart;
	
	fprintf(pf, "Total timing session took:  %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur);
	fprintf(pf, "\n\n");
	
	Tracef("Total timing session took:  %u cycles = %f seconds\n", (end_clk.LowPart - start_clk.LowPart), dur);
	Tracef("\n\n");
	
	for (n = 0; n < NMETHOD; ++n)
	{
		for (i = 0; i < NBATCHES; ++i)
		{
			fprintf(pf, "method %d:\n", n);
			fprintf(pf, "  %s", method[n][i].m_csName);
			fprintf(pf, "  tot:   %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); 
			
			Tracef("method %d:\n", n);
			Tracef("  %s", method[n][i].m_csName);
			Tracef("  tot:   %u %u\n", method[n][i].m_interval_sum.HighPart, method[n][i].m_interval_sum.LowPart); 
			
			dur = ((double)method[n][i].m_interval_sum.LowPart) / ((double)method[n][i].m_nSamples * (double)freq.LowPart);
			
			fprintf(pf, "  avg:   %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples);
			fprintf(pf, "  avg time:  %f sec\n", dur);
			
			Tracef("  avg:   %u\n", method[n][i].m_interval_sum.LowPart / method[n][i].m_nSamples);
			Tracef("  avg time:  %f sec\n", dur);
		}
		
		fprintf(pf, "\n\n");
		Tracef("\n\n");
	}
	
	fclose(pf);
	
	MessageBeep(MB_OK);
	//BOOL QueryPerformanceFrequency(
	//  LARGE_INTEGER *lpFrequency   // address of current frequency
	//);
}

inline void GetColorBlockColors_m2(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, 
								   Color8888 * col_2, Color8888 * col_3,
								   WORD & wrd )
{
	// method 2
	// freak variable bit structure method
	// normal math
	Color565 * pCol;
	
	pCol = (Color565*) & (pBlock->col0);
	
	col_0->a = 0xff;
	col_0->r = pCol->nRed;
	col_0->r <<= 3;				// shift to full precision
	col_0->g = pCol->nGreen;
	col_0->g <<= 2;
	col_0->b = pCol->nBlue;
	col_0->b <<= 3;
	
	pCol = (Color565*) & (pBlock->col1);
	col_1->a = 0xff;
	col_1->r = pCol->nRed;
	col_1->r <<= 3;				// shift to full precision
	col_1->g = pCol->nGreen;
	col_1->g <<= 2;
	col_1->b = pCol->nBlue;
	col_1->b <<= 3;
	
	if (pBlock->col0 > pBlock->col1)
	{
		// Four-color block: derive the other two colors.    
		// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block.
		wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3;
		// no +1 for rounding
		// as bits have been shifted to 888
		col_2->r = (BYTE)wrd;
		
		wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3;
		col_2->g = (BYTE)wrd;
		
		wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3;
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3;
		col_3->r = (BYTE)wrd;
		
		wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3;
		col_3->g = (BYTE)wrd;
		
		wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3;
		col_3->b = (BYTE)wrd;
		col_3->a = 0xff;
		
	}
	else
	{
		// Three-color block: derive the other color.
		// 00 = color_0,  01 = color_1,  10 = color_2,  
		// 11 = transparent.
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block. 
		
		// explicit for each component, unlike some refrasts...
		
		// Tracef("block has alpha\n");
		wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2;
		col_2->r = (BYTE)wrd;
		wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2;
		col_2->g = (BYTE)wrd;
		wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2;
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		col_3->r = 0x00;		// random color to indicate alpha
		col_3->g = 0xff;
		col_3->b = 0xff;
		col_3->a = 0x00;
	}
}



inline void GetColorBlockColors_m3(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, 
								   Color8888 * col_2, Color8888 * col_3,
								   WORD & wrd )
{
	// method 3
	//////////////////////////////////////////////////////
	// super-freak variable bit structure with
	//  Cool Math Trick (tm)

	// Do 2/3 1/3 math BEFORE bit shift on the whole DWORD
	// as the fields will NEVER carry into the next
	//  or overflow!! =) 
	
	Color565 * pCol;
	
	pCol = (Color565*) & (pBlock->col0);
	
	col_0->a = 0x00;			// must set to 0 to avoid overflow in DWORD add
	col_0->r = pCol->nRed;
	col_0->g = pCol->nGreen;
	col_0->b = pCol->nBlue;
	
	pCol = (Color565*) & (pBlock->col1);
	col_1->a = 0x00;
	col_1->r = pCol->nRed;
	col_1->g = pCol->nGreen;
	col_1->b = pCol->nBlue;
	
	if (pBlock->col0 > pBlock->col1)
	{
		*((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1)));
		
		*((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2);
		
		// now shift to appropriate precision & divide by 3.
		col_2->r = ((WORD) col_2->r << 3) / (WORD)3;
		col_2->g = ((WORD) col_2->g << 2) / (WORD)3;
		col_2->b = ((WORD) col_2->b << 3) / (WORD)3;
		
		col_3->r = ((WORD) col_3->r << 3) / (WORD)3;
		col_3->g = ((WORD) col_3->g << 2) / (WORD)3;
		col_3->b = ((WORD) col_3->b << 3) / (WORD)3;

		col_0->a = 0xff;		// now set appropriate alpha
		col_1->a = 0xff;
		col_2->a = 0xff;
		col_3->a = 0xff;
	}
	else
	{
		*((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)));
		
		// now shift to appropriate precision & divide by 2.
		// << 3) / 2 == << 2
		// << 2) / 2 == << 1
		col_2->r = ((WORD) col_2->r << 2);
		col_2->g = ((WORD) col_2->g << 1);
		col_2->b = ((WORD) col_2->b << 2);
		
		col_2->a = 0xff;
		
		col_3->a = 0x00;	// 
		col_3->r = 0x00;	// random color to indicate alpha
		col_3->g = 0xff;
		col_3->b = 0xff;
	}
	
	// now shift orig color components
	col_0->r <<= 3;
	col_0->g <<= 2;
	col_0->b <<= 3;
	
	col_1->r <<= 3;
	col_1->g <<= 2;
	col_1->b <<= 3;
}


inline void GetColorBlockColors_m4(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, 
								   Color8888 * col_2, Color8888 * col_3,
								   WORD & wrd )
{
	
	// m1 color extraction from 5-6-5
	// m3 color math on DWORD before bit shift to full precision
	wrd = pBlock->col0;
	col_0->a = 0x00;			// must set to 0 to avoid possible overflow & carry to next field in DWORD add
	
	// extract r,g,b bits
	col_0->b = (unsigned char) wrd & 0x1f;			// 0x1f = 0001 1111  to mask out upper 3 bits
	wrd >>= 5;
	col_0->g = (unsigned char) wrd & 0x3f;			// 0x3f = 0011 1111  to mask out upper 2 bits
	wrd >>= 6;
	col_0->r = (unsigned char) wrd & 0x1f;
	
	
	// same for col # 2:
	wrd = pBlock->col1;
	col_1->a = 0x00;			// must set to 0 to avoid possible overflow in DWORD add
	
	// extract r,g,b bits
	col_1->b = (unsigned char) wrd & 0x1f;
	wrd >>= 5;
	col_1->g = (unsigned char) wrd & 0x3f;
	wrd >>= 6;
	col_1->r = (unsigned char) wrd & 0x1f;

	if (pBlock->col0 > pBlock->col1)
	{
		*((DWORD*)col_2) = ((*((DWORD*)col_0)) * 2 + (*((DWORD*)col_1)));
		*((DWORD*)col_3) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)) * 2);
		
		// shift to appropriate precision & divide by 3.
		col_2->r = ((WORD) col_2->r << 3) / (WORD)3;
		col_2->g = ((WORD) col_2->g << 2) / (WORD)3;
		col_2->b = ((WORD) col_2->b << 3) / (WORD)3;
		
		col_3->r = ((WORD) col_3->r << 3) / (WORD)3;
		col_3->g = ((WORD) col_3->g << 2) / (WORD)3;
		col_3->b = ((WORD) col_3->b << 3) / (WORD)3;
		
		col_0->a = 0xff;		// set appropriate alpha
		col_1->a = 0xff;
		col_2->a = 0xff;
		col_3->a = 0xff;
	}
	else
	{
		*((DWORD*)col_2) = ((*((DWORD*)col_0)) + (*((DWORD*)col_1)));
		
		// shift to appropriate precision & divide by 2.
		// << 3) / 2 == << 2
		// << 2) / 2 == << 1
		col_2->r = ((WORD) col_2->r << 2);
		col_2->g = ((WORD) col_2->g << 1);
		col_2->b = ((WORD) col_2->b << 2);
		
		col_2->a = 0xff;
		
		col_3->a = 0x00;	// 
		col_3->r = 0x00;	// random color to indicate alpha
		col_3->g = 0xff;
		col_3->b = 0xff;
	}
	
	// shift orig color components to full precision
	col_0->r <<= 3;
	col_0->g <<= 2;
	col_0->b <<= 3;
	
	col_1->r <<= 3;
	col_1->g <<= 2;
	col_1->b <<= 3;
}


inline void GetColorBlockColors_m1(DXTColBlock * pBlock, Color8888 * col_0, Color8888 * col_1, 
								   Color8888 * col_2, Color8888 * col_3,
								   WORD & wrd )
{
	
	// Method 1:
	// Shifty method
	wrd = pBlock->col0;
	col_0->a = 0xff;
	
	// extract r,g,b bits
	col_0->b = (unsigned char) wrd;
	col_0->b <<= 3;		// shift to full precision
	wrd >>= 5;
	col_0->g = (unsigned char) wrd;
	col_0->g <<= 2;		// shift to full precision
	wrd >>= 6;
	col_0->r = (unsigned char) wrd;
	col_0->r <<= 3;		// shift to full precision

	// same for col # 2:
	wrd = pBlock->col1;
	col_1->a = 0xff;
	
	// extract r,g,b bits
	col_1->b = (unsigned char) wrd;
	col_1->b <<= 3;		// shift to full precision
	wrd >>= 5;
	col_1->g = (unsigned char) wrd;
	col_1->g <<= 2;		// shift to full precision
	wrd >>= 6;
	col_1->r = (unsigned char) wrd;
	col_1->r <<= 3;		// shift to full precision

	// use this for all but the super-freak math method
	if (pBlock->col0 > pBlock->col1)
	{
		// Four-color block: derive the other two colors.    
		// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block.
		
		wrd = ((WORD) col_0->r * 2 + (WORD) col_1->r) / 3;
		// no +1 for rounding
		// as bits have been shifted to 888
		col_2->r = (BYTE)wrd;
		
		wrd = ((WORD) col_0->g * 2 + (WORD) col_1->g) / 3;
		col_2->g = (BYTE)wrd;
		
		wrd = ((WORD) col_0->b * 2 + (WORD) col_1->b) / 3;
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		wrd = ((WORD) col_0->r + (WORD) col_1->r * 2) / 3;
		col_3->r = (BYTE)wrd;
		
		wrd = ((WORD) col_0->g + (WORD) col_1->g * 2) / 3;
		col_3->g = (BYTE)wrd;
		
		wrd = ((WORD) col_0->b + (WORD) col_1->b * 2) / 3;
		col_3->b = (BYTE)wrd;
		col_3->a = 0xff;
	}
	else
	{
		// Three-color block: derive the other color.
		// 00 = color_0,  01 = color_1,  10 = color_2,  
		// 11 = transparent.
		// These two bit codes correspond to the 2-bit fields 
		// stored in the 64-bit block. 
		
		// explicit for each component, unlike some refrasts...
		
		// Tracef("block has alpha\n");
		
		wrd = ((WORD) col_0->r + (WORD) col_1->r) / 2;
		col_2->r = (BYTE)wrd;
		wrd = ((WORD) col_0->g + (WORD) col_1->g) / 2;
		col_2->g = (BYTE)wrd;
		wrd = ((WORD) col_0->b + (WORD) col_1->b) / 2;
		col_2->b = (BYTE)wrd;
		col_2->a = 0xff;
		
		col_3->r = 0x00;		// random color to indicate alpha
		col_3->g = 0xff;
		col_3->b = 0xff;
		col_3->a = 0x00;
	}
}	//  Get color block colors (...)

void CDXTCImage::Time_Decomp5_01(int ntimes, TimingInfo * info)
{
	int n;
	
	info->m_nSamples = 0;
	info->m_interval_sum.QuadPart = 0;
	info->m_csName.Format("Timing decomp method 1:  bit shift, for %d times\n", ntimes);

	for (n = 0; n < ntimes; n++)
	{
		QueryPerformanceCounter(& info->m_start_clk);

		int xblocks, yblocks;
		
		xblocks = m_DDSD.dwWidth / 4;
		yblocks = m_DDSD.dwHeight / 4;

		int i,j;
		
		DWORD * pBase  = (DWORD*) m_pDecompBytes;
		DWORD * pImPos = (DWORD*) pBase;			// pos in decompressed data
		WORD  * pPos   = (WORD*) m_pCompBytes;	// pos in compressed data
		
		DXTColBlock				* pBlock;
		DXTAlphaBlock3BitLinear * pAlphaBlock;
		
		Color8888 col_0, col_1, col_2, col_3;
		WORD wrd;
		
		// fill alphazero with appropriate value to zero out alpha when
		//  alphazero is ANDed with the image color 32 bit DWORD:
		col_0.a = 0;
		col_0.r = col_0.g = col_0.b = 0xff;
		DWORD alphazero = *((DWORD*) &col_0);

		// ** See DecompressDXT5 code for comments!!
		for (j = 0; j < yblocks; ++j)
		{
			pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16);
			for (i = 0; i < xblocks; ++i, ++pBlock)
			{
				pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
				pBlock++;
				
				GetColorBlockColors_m1(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
				
				pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4);
				DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1,
					(DWORD*)&col_2, (DWORD*)&col_3);
				DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero);
			}
		}

		QueryPerformanceCounter(& info->m_end_clk);
		
		info->m_nSamples ++;
		info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart;
	}
}


void CDXTCImage::Time_Decomp5_02(int ntimes, TimingInfo * info)
{
	int n;

	info->m_nSamples = 0;
	info->m_interval_sum.QuadPart = 0;
	info->m_csName.Format("Timing decomp method 2:  bit field struct, for %d times\n", ntimes);

	for (n = 0; n < ntimes; n++)
	{
		QueryPerformanceCounter(& info->m_start_clk);
		
		int xblocks, yblocks;
		xblocks = m_DDSD.dwWidth / 4;
		yblocks = m_DDSD.dwHeight / 4;		
		int i,j;
		DWORD * pBase  = (DWORD*) m_pDecompBytes;
		DWORD * pImPos = (DWORD*) pBase;			// pos in decompressed data
		WORD  * pPos   = (WORD*)  m_pCompBytes;	// pos in compressed data
		DXTColBlock				* pBlock;
		DXTAlphaBlock3BitLinear * pAlphaBlock;
		Color8888 col_0, col_1, col_2, col_3;
		WORD wrd;
		// fill alphazero with appropriate value to zero out alpha when
		//  alphazero is ANDed with the image color 32 bit DWORD:
		col_0.a = 0;
		col_0.r = col_0.g = col_0.b = 0xff;
		DWORD alphazero = *((DWORD*) &col_0);
		
		// ** See DecompressDXT5 code for comments!!
		for (j = 0; j < yblocks; ++j)
		{
			pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16);
			for (i = 0; i < xblocks; ++i, ++pBlock)
			{
				pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
				pBlock++;
				
				GetColorBlockColors_m2(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
				
				pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4);
				DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1,
					(DWORD*)&col_2, (DWORD*)&col_3);
				DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero);
			}
		}
		
		QueryPerformanceCounter(& info->m_end_clk);
		
		info->m_nSamples ++;
		info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart;
	}
}

void CDXTCImage::Time_Decomp5_03(int ntimes, TimingInfo * info)
{
	int n;
	
	info->m_nSamples = 0;
	info->m_interval_sum.QuadPart = 0;
	info->m_csName.Format("Timing decomp method 3:  bit field struct w/ pre-shift math, for %d times\n", ntimes);

	for (n = 0; n < ntimes; n++)
	{
		QueryPerformanceCounter(& info->m_start_clk);
		
		int xblocks, yblocks;
		xblocks = m_DDSD.dwWidth / 4;
		yblocks = m_DDSD.dwHeight / 4;		
		int i,j;
		DWORD * pBase  = (DWORD*)  m_pDecompBytes;
		DWORD * pImPos = (DWORD*)  pBase;			// pos in decompressed data
		WORD  * pPos   = (WORD*)   m_pCompBytes;	// pos in compressed data
		DXTColBlock				* pBlock;
		DXTAlphaBlock3BitLinear * pAlphaBlock;
		Color8888 col_0, col_1, col_2, col_3;
		WORD wrd;
		
		// fill alphazero with appropriate value to zero out alpha when
		//  alphazero is ANDed with the image color 32 bit DWORD:
		col_0.a = 0;
		col_0.r = col_0.g = col_0.b = 0xff;
		DWORD alphazero = *((DWORD*) &col_0);
		
		// ** See DecompressDXT5 code for comments!!
		for (j = 0; j < yblocks; ++j)
		{
			pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16);
			for (i = 0; i < xblocks; ++i, ++pBlock)
			{
				pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
				pBlock++;
				
				GetColorBlockColors_m3(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
				
				pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4);
				DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1,
					(DWORD*)&col_2, (DWORD*)&col_3);
				DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero);
			}
		}
		
		QueryPerformanceCounter(& info->m_end_clk);
		
		info->m_nSamples ++;
		info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart;
	}
}


void CDXTCImage::Time_Decomp5_04(int ntimes, TimingInfo * info)
{
	int n;
	
	info->m_nSamples = 0;
	info->m_interval_sum.QuadPart = 0;
	info->m_csName.Format("Timing decomp method 4:  shift extract w/ pre-shift math, for %d times\n", ntimes);
	
	QueryPerformanceCounter(& info->m_start_clk);
	
	for (n = 0; n < ntimes; n++)
	{
		int xblocks, yblocks;
		xblocks = m_DDSD.dwWidth / 4;
		yblocks = m_DDSD.dwHeight / 4;		
		int i,j;
		DWORD * pBase  = (DWORD*)  m_pDecompBytes;
		DWORD * pImPos = (DWORD*)  pBase;			// pos in decompressed data
		WORD  * pPos   = (WORD*)   m_pCompBytes;	// pos in compressed data
		DXTColBlock				* pBlock;
		DXTAlphaBlock3BitLinear * pAlphaBlock;
		Color8888 col_0, col_1, col_2, col_3;
		WORD wrd;
		// fill alphazero with appropriate value to zero out alpha when
		//  alphazero is ANDed with the image color 32 bit DWORD:
		col_0.a = 0;
		col_0.r = col_0.g = col_0.b = 0xff;
		DWORD alphazero = *((DWORD*) &col_0);
		
		// ** See DecompressDXT5 code for comments!!
		for (j = 0; j < yblocks; ++j)
		{
			pBlock = (DXTColBlock*) ((DWORD)m_pCompBytes + j * xblocks * 16);
			for (i = 0; i < xblocks; ++i, ++pBlock)
			{
				pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
				pBlock++;
				
				GetColorBlockColors_m4(pBlock, &col_0, &col_1, &col_2, &col_3, wrd);
				
				pImPos = (DWORD*)((DWORD)pBase + i*16 + (j*4) * m_nWidth * 4);
				DecodeColorBlock(pImPos, pBlock, m_nWidth, (DWORD*)&col_0, (DWORD*)&col_1,
					(DWORD*)&col_2, (DWORD*)&col_3);
				DecodeAlpha3BitLinear(pImPos, pAlphaBlock, m_nWidth, alphazero);
			}
		}
	}
	
	QueryPerformanceCounter(& info->m_end_clk);
	
	info->m_nSamples = ntimes;
	info->m_interval_sum.QuadPart += info->m_end_clk.QuadPart - info->m_start_clk.QuadPart;
	
}
*/
